﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
using SimpleMvcCaptcha.Helper;

namespace SimpleMvcCaptcha.Utils
{
    public static class CaptchaUtils
    {
        /// <summary>
        /// Captcha image generation
        /// </summary>
        /// <param name="captchaId">Id of a current captcha expression</param>
        /// <returns>Byte array of an image</returns>
        public static byte[] GetImage(string captchaId)
        {
            return GetImage(captchaId, new CaptchaParameters());
        }

        /// <summary>
        /// Captcha image generation
        /// </summary>
        /// <param name="captchaId">Id of a current captcha expression</param>
        /// <param name="parameters">Parameters obkect</param>
        /// <returns>Byte array of an image</returns>
        public static byte[] GetImage(string captchaId, CaptchaParameters parameters)
        {
            // Retreiving captcha object from session store
            var captcha = HttpContext.Current.Session[captchaId] as Captcha;
            if (captcha == null)
                return new byte[0];
            
            // Initializing bitmap variables
            var bitmap = new Bitmap(parameters.Width, parameters.Height, PixelFormat.Format32bppArgb);
            var g = Graphics.FromImage(bitmap);
            var rect = new Rectangle(0, 0, parameters.Width, parameters.Height);
            var whiteBrush = new SolidBrush(Color.White);
            var random = new Random();
            var textBrush = new SolidBrush(Color.FromArgb(random.Next(200), random.Next(200), random.Next(200)));

            // Drawing rectangle for captcha
            g.FillRectangle(whiteBrush, rect);

            // Drawing captcha expression
            g.DrawString(captcha.Expresion, new Font(parameters.FontName, parameters.FontSize), textBrush, new PointF(10, 0));
            GenerateRandomLines(g, parameters.Width, parameters.Height, parameters);

            // Putting bitmap into memory as GIF
            var ms = new MemoryStream();
            bitmap.Save(ms, ImageFormat.Gif);

            return ms.ToArray();
        }

        /// <summary>
        /// Validates input
        /// </summary>
        /// <returns>true - validation succeeded \nfalse - validation failed</returns>
        public static bool Validate()
        {
            var ctx = HttpContext.Current;

            var captchaAnswer = ctx.Request.Form["captchaAnswer"];
            var captchaHidden = ctx.Request.Form["captchaId"];

            // If input is not empty
            if(!String.IsNullOrEmpty(captchaAnswer) && !String.IsNullOrEmpty(captchaHidden))
            {
                var captcha = ctx.Session[captchaHidden] as Captcha;
                ctx.Session.Remove(captchaHidden);

                return captcha != null && captchaAnswer == captcha.Result;
            }

            return false;
        }

        /// <summary>
        /// Generatel random lines on an image
        /// </summary>
        /// <param name="graphics">Graphics object</param>
        /// <param name="maxX">Maximum X coord</param>
        /// <param name="maxY">Maximum Y coord</param>
        /// <param name="parameters"> </param>
        private static void GenerateRandomLines(Graphics graphics, int maxX, int maxY, CaptchaParameters parameters)
        {
            var random = new Random();
            var brush = new SolidBrush(GetRandomColor());
            var pen = new Pen(brush, 1);
            var line = new PointF[parameters.MaxRandomLines];

            // Creating random points for captcha's noise
            for (var i = 0; i < parameters.MaxRandomLines; i++)
                line[i] = i%2 == 0
                              ? new PointF(random.Next(0, maxX/2), random.Next(0, maxY))
                              : new PointF(random.Next(maxX/2, maxX), random.Next(0, maxY));

            // Drawing noise lines
            graphics.DrawLines(pen, line);
        }

        /// <summary>
        /// Generates random color
        /// </summary>
        /// <returns>Color object</returns>
        private static Color GetRandomColor()
        {
            var random = new Random(DateTime.Now.Millisecond);
            return Color.FromArgb(random.Next(200), random.Next(200), random.Next(200));
        }
    }
}
